package com.dhms.vostok1.ui.main

import android.Manifest.permission.*
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothAdapter.*
import android.bluetooth.BluetoothManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.dhms.lib.app.LibApplication
import com.dhms.uikit.media.MediaActivity
import com.dhms.uikit.media.MediaType
import com.dhms.vostok1.MainApplication
import com.dhms.vostok1.R
import com.dhms.vostok1.base.SingleLiveData
import com.dhms.vostok1.data.ApiState
import com.dhms.vostok1.data.spot_patrol.*
import com.dhms.vostok1.databinding.ActivityMainBinding
import com.dhms.vostok1.model.*
import com.dhms.vostok1.network.MoshiObject
import com.dhms.vostok1.repository.CheckInstrumentRepository
import com.dhms.vostok1.repository.FaultRepository
import com.dhms.vostok1.repository.SpcTaskRepository
import com.dhms.vostok1.service.net.NetworkApi
import com.dhms.vostok1.ui.login.LoginActivity
import com.dhms.vostok1.utils.NetworkState
import com.dhms.vostok1.utils.hide
import com.dhms.vostok1.utils.show
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.permissionx.guolindev.PermissionX
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaType
import java.io.File
import java.util.concurrent.CountDownLatch

class MainActivity : AppCompatActivity(),MainActivityInterface{

    private lateinit var _binding: ActivityMainBinding
    val binding get() = _binding

    lateinit var navHostFragment: NavHostFragment

    private val userViewModel: UserViewModel by viewModels()
    private val messageCenterViewModel: MessageCenterViewModel by viewModels()
    private val settingViewModel: SettingViewModel by viewModels()
    private val faultViewModel: FaultViewModel by viewModels {
        FaultViewModelFactory(FaultRepository.getInstance((application as MainApplication).database.faultDao()))
    }
    private val faultDetailViewModel: FaultDetailViewModel by viewModels {
        FaultDetailViewModelFactory(FaultRepository.getInstance((application as MainApplication).database.faultDao()))
    }
    private val checkInstrumentViewModel: CheckInstrumentViewModel by viewModels {
        CheckInstrumentViewModelFactory(
            application,
            CheckInstrumentRepository.getInstance((application as MainApplication).database.checkInstrumentDao()),
        )
    }
    private val spcViewModel: SpotCheckViewModel by viewModels {
        SpotCheckViewModelFactory()
    }
    private val mediaViewModel: MediaViewModel by viewModels()

    private var preToastCoroutine: Job? = null

    private lateinit var badgeDrawable: BadgeDrawable

    private lateinit var broadcastReceiver: BroadcastReceiver

    private var requestUserInfo = false
    private var downloadSpcTask = false

    private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        bluetoothManager.adapter
    }
    private lateinit var requestEnableBluetoothLauncher: ActivityResultLauncher<Intent>
    private lateinit var bluetoothBroadcastReceiver: BluetoothBroadcastReceiver
    private val bluetoothBroadcastIntentFilter: IntentFilter by lazy {
        IntentFilter().apply {
            addAction(ACTION_STATE_CHANGED) // listen bt state changed
        }
    }

    val selectMemberEvent=SingleLiveData<String>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        badgeDrawable = BadgeDrawable.create(this)
        badgeDrawable.maxCharacterCount = 3

        initBluetooth()

        getSettings()

        setBroadcastReceiver()

        setNavigation()

        setMessageCenterListener()

        monitorNetworkChange()

        prepareData()
    }

    private fun monitorNetworkChange() {
        /*判断网络状态变化*/
        WebSocketViewModel.instance.networkChange.observe(this) {
            when (it) {
                NetworkState.NETWORK -> {
                    if (!requestUserInfo) {
                        userViewModel.getUserInformation()
                        userViewModel.getCustomerInfo()
                        getMessageCount()
                        requestUserInfo = true
                    }
                    if (WebSocketViewModel.instance.offlineModeState.value == OfflineModeState.OFFLINE) {
                        WebSocketViewModel.instance.setOfflineModeState(OfflineModeState.NONE)
                    }
                    uploadSpcTask()
                }
                NetworkState.NETWORK_NO -> {
                    if (WebSocketViewModel.instance.offlineModeState.value == OfflineModeState.NONE) {
                        WebSocketViewModel.instance.setOfflineModeState(OfflineModeState.OFFLINE)
                    }
                }
                else -> {}
            }
        }
    }

    private fun initBluetooth() {
        bluetoothBroadcastReceiver = BluetoothBroadcastReceiver()

        requestEnableBluetoothLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode != RESULT_OK) {
                    showToast(R.drawable.ic_fail, "请先打开蓝牙！", timeOut = 1)
                }
            }
    }

    private fun setBroadcastReceiver() {
        broadcastReceiver = MainBroadcastReceiver {
            Toast.makeText(this, "登录信息过期，请重新登录！", Toast.LENGTH_SHORT).show()
            logout()
        }
        val filter = IntentFilter().apply {
            addAction(TOKEN_EXPIRED_BROADCAST_NAME)
        }
        LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, filter)
    }

    private fun setNavigation() {
        val navView: BottomNavigationView = binding.bottomNavigation

        navHostFragment =
            supportFragmentManager.findFragmentById(R.id.nav_main_fragment) as NavHostFragment
        val navController = navHostFragment.navController
        navView.setupWithNavController(navHostFragment.navController)

        navController.addOnDestinationChangedListener { _, destination, _ ->
            hideToast()
            when (destination.id) {
                in HOME_NAV_LIST -> {
                    getMessageCount()
                    navView.show()
                }
                else -> {
                    // 屏幕方向改变时使用自定义动画隐藏会抛出view还未layout就draw的异常，简单接住直接隐藏掉
                    try {
                        navView.hide()
                    } catch (e: Exception) {
                        navView.visibility = View.GONE
                    }
                }
            }
        }
    }

    private fun getUserInfo() {
//        val sharedPref =
//            this.getSharedPreferences(
//                getString(R.string.user_preference_file_key),
//                Context.MODE_PRIVATE
//            )
        userViewModel.setContextAndSharePref(this, LibApplication.mmkv)

        userViewModel.getUserInfoResult.observe(this) { getUserInfoResult ->
            if (getUserInfoResult?.state == ApiState.ERROR) {
                showToast(R.drawable.ic_fail, "获取用户信息失败，请重新登录！", false, 1)
                lifecycleScope.launch {
                    delay(1000)
                    logout()
                }
            }
        }

        userViewModel.getSavedUserInfo()

        if (NetworkApi.baseUrl == null) {
            Log.i(TAG, "baseUrl为null")
            Log.i(TAG, "获取缓存的url:${settingViewModel.baseUrl}")
        }
        WebSocketViewModel.instance.createWebSocket()

    }

    private fun getSettings() {
//        val sharedPref =
//            this.getSharedPreferences(
//                getString(R.string.setting_preference_file_key),
//                Context.MODE_PRIVATE
//            )
        settingViewModel.setSharedPreferences(LibApplication.mmkv)
        settingViewModel.getSettings()
    }

    private fun prepareData() {
        getUserInfo()

        Log.d(
            TAG,
            "Init view models: $faultViewModel, $faultDetailViewModel, $checkInstrumentViewModel."
        )
    }

    private fun prepareOnlineData() {
        lifecycleScope.launch {
            spcViewModel.downloadOfflineSpcTasks()
        }
    }

    private fun uploadSpcTask() {
        lifecycleScope.launch {
            /*从数据库获取 数据*/
            val items = SpcTaskRepository.getInstance().getCompletedSpcTaskListData()
            var updateError = false

            /*上传物联平台任务*/
            SpcTaskRepository.getInstance().getReportTerminalTaskData().forEach {
                it.terminalInfoStr?.let { terminalInfoStr ->
                    MoshiObject.moshi.adapter(ReportTerminalInfo::class.java)
                        .fromJson(terminalInfoStr)?.let { info ->
                            val res = NetworkApi.uploadTerminalInfo(info)
                            if (res.exceptionOrNull() == null) {
                                SpcTaskRepository.getInstance().deleteReportTerminalTaskData(it.id)
                            }
                        }
                }
            }

            if (items.isNotEmpty()) {
                val countDownLatch = CountDownLatch(items.size)
                var executorIndex = 0
                WebSocketViewModel.instance.setOfflineModeState(OfflineModeState.SYNCHRONIZING)

                items.forEach { taskData ->
                    taskData.groupID?.let { groupID ->
                        executorIndex += 1
                        WebSocketViewModel.instance.setSyncDataContent("（$executorIndex/${items.size}）")
                        if (!uploadTaskData(groupID, taskData)) {
                            updateError = true
                        }
                    }
                    countDownLatch.countDown()
                }

                countDownLatch.await()
                //等待上传任务结束，获取一个结果
                if (updateError) {
                    WebSocketViewModel.instance.setOfflineModeState(OfflineModeState.ERROR)
                } else {
                    //清空数据
                    SpcTaskRepository.getInstance().deleteAllData()
                    spcViewModel.downloadOfflineSpcTasks()
                    WebSocketViewModel.instance.setOfflineModeState(OfflineModeState.COMPLETE)
                    delay(2000L)
                    val mode =
                        if (WebSocketViewModel.instance.networkChange.value == NetworkState.NETWORK_NO) OfflineModeState.OFFLINE else OfflineModeState.NONE
                    WebSocketViewModel.instance.setOfflineModeState(mode)
                }
            } else {
                //清空数据
                SpcTaskRepository.getInstance().deleteAllData()
                spcViewModel.downloadOfflineSpcTasks()
            }

            if (WebSocketViewModel.instance.networkChange.value != NetworkState.NETWORK_NO) {
                if (!downloadSpcTask) {
                    downloadSpcTask = true
                    // to update the online data every time when connection becomes online
                    prepareOnlineData()
                }
            }

        }
    }

    private suspend fun uploadTaskData(groupID: String, taskData: TaskData): Boolean {
        var errorMessage: String? = null
        taskData.patrolItems?.spotDetector?.forEach { spotData ->
            spotData.tsData?.let {
                MoshiObject.moshi.adapter(ReportTsData::class.java).fromJson(it)
                    ?.let { reportTsData ->
                        val e = checkInstrumentViewModel.uploadTerminalTSData(reportTsData)
                        if (e != null) {
                            errorMessage = "温度数据上传失败"
                        }
                    }
            }

            spotData.blockData?.let {
                MoshiObject.moshi.adapter(ReportBlockData::class.java).fromJson(it)
                    ?.let { reportBlockData ->
                        val e = checkInstrumentViewModel.uploadTerminalBlockData(reportBlockData)
                        if (e != null) {
                            errorMessage = "振动数据上传失败"
                        }
                    }
            }
        }

        var updateTaskData: TaskData? = taskData
        taskData.patrolItems?.fiveSenses?.forEach { fiveSenses ->
            fiveSenses.abnormalOss.forEach { ossData ->
                // 在线 地址为 空 & 本地 地址不为空
                if (ossData.url.isEmpty() && ossData.localUrl.isNotEmpty()) {
                    val uri = Uri.fromFile(File(ossData.localUrl))
                    val ossFilePath = mediaViewModel.uploadFile(
                        uri,
                        when (AttachmentType.convertToMediaType(ossData.type)) {
                            MediaType.VIDEO -> "video/${
                                MediaActivity.VIDEO_EXTENSION.split(".").last()
                            }".toMediaType()
                            MediaType.PHOTO -> "image/${
                                MediaActivity.PHOTO_EXTENSION.split(".").last()
                            }".toMediaType()
                            MediaType.AUDIO -> "audio/${
                                MediaActivity.AUDIO_EXTENSION.split(".").last()
                            }".toMediaType()
                            else -> "*/*".toMediaType()
                        }
                    )

                    var ossThumbnail: String? = null
                    if (ossData.firstFrame.isNotEmpty() && !ossData.firstFrame.startsWith("http")) {
                        ossThumbnail = mediaViewModel.uploadFile(
                            Uri.fromFile(File(ossData.firstFrame)), "image/${
                                MediaActivity.PHOTO_EXTENSION.split(".").last()
                            }".toMediaType()
                        )
                    }

                    if (ossFilePath.isNullOrBlank()) {
                        errorMessage = "附件上传失败"
                    }
                    ossFilePath?.let { onlineUrl ->
                        //更新数据库
                        updateTaskData = SpcTaskRepository.getInstance()
                            .updateAbnormalOssData(
                                taskData,
                                ossData.localUrl,
                                onlineUrl,
                                ossThumbnail ?: ""
                            )
                    }
                }
            }
        }
        //从数据库重新获取一个新的taskData
//        val updateTaskData = SpcTaskRepository.getInstance()
//            .getSpcTaskData(taskData.groupID ?: "", taskData.taskId ?: 0) ?: taskData
        updateTaskData?.patrolItems?.fiveSenses?.forEach { fiveSenses ->
            fiveSenses.abnormalOss.forEach { ossData ->
                // 在线 地址为 空 & 本地 地址不为空
                var url = ossData.url
                var localUrl = ossData.localUrl
                Log.d(TAG, "abnormalOss: ${url} - ${localUrl}")
            }
        }
        updateTaskData?.let {
            it
            val res =
                NetworkApi.updateTask(it)
            Log.d(TAG, "res: $res")
            val e = res.exceptionOrNull()
            if (e != null) {
                Log.e(
                    TAG,
                    "Update $groupID detail data error: $e"
                )
                errorMessage = "任务上传失败"
            }
        }

        if (errorMessage != null) {
            SpcTaskRepository.getInstance()
                .updateSpcTaskDataError(
                    groupID,
                    taskData.taskId ?: 0,
                    errorMessage!!
                )
        } else {
            SpcTaskRepository.getInstance()
                .deleteSpcTaskData(groupID, taskData.taskId ?: 0)
        }

        return errorMessage == null
    }

    private fun clearData() {

    }

    override fun logout() {
        requestUserInfo = false
        userViewModel.logout()
        WebSocketViewModel.instance.closeWebSocket()
        val intent = Intent(
            this,
            LoginActivity::class.java
        ).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
        this.startActivity(intent)
    }

    override fun memberEventObserve(owner: LifecycleOwner, observer: Observer<Any>) {
        selectMemberEvent.observe(owner,observer)
    }

    override fun getHomeNavList(): List<Int> {
        return HOME_NAV_LIST
    }

    override fun bottomNavigationShow() {
        runOnUiThread{
            binding.bottomNavigation.show()
        }
    }

    override fun showToast(
        icon: Int?,
        message: String?,
        isLoading: Boolean,
        timeOut: Int,
        isShowing: Boolean
    ) {
        if (icon != null) {
            binding.toast.icon = ResourcesCompat.getDrawable(resources, icon, null)
        }
        binding.toast.message = message
        binding.toast.isLoading = isLoading
        binding.toast.visibility = isShowing
        // 把之前的协程取消，以免之前的取消动作影响当前toast
        preToastCoroutine?.cancel()
        if (timeOut != 0) {
            preToastCoroutine = lifecycleScope.launch {
                delay(timeOut * 1000L)
                binding.toast.visibility = false
            }
        } else {
            // 常驻的没有协程对其关闭，把pre协程Job置null
            preToastCoroutine = null
        }
    }

    override fun hideToast() {
        preToastCoroutine?.cancel()
        binding.toast.visibility = false
        preToastCoroutine = null
    }

    private fun setMessageCenterListener() {
        messageCenterViewModel.messageCount.observe(this) {
            if (it == 0) {
                badgeDrawable.clearNumber()
                badgeDrawable.isVisible = false
                return@observe
            }
            badgeDrawable.number = it
            badgeDrawable.isVisible = true
        }
    }

    private fun getMessageCount() {
        if (WebSocketViewModel.instance.networkChange.value == NetworkState.NETWORK) {
            userViewModel.userInfo.value?.userId?.let {
                messageCenterViewModel.getMessages()
            }
        }
    }

    @SuppressLint("UnsafeOptInUsageError")
    override fun setNotificationBadge(toolbar: MaterialToolbar) {
        BadgeUtils.attachBadgeDrawable(badgeDrawable, toolbar, R.id.menu_notification)
//        toolbar.setOnMenuItemClickListener {
//            when (it.itemId) {
//                R.id.menu_notification -> {
//                    true
//                }
//                else -> {
//                    false
//                }
//            }
//        }
    }

    fun prepareBluetooth(
        onBluetoothDisabled: (() -> Unit)? = null,
        onBluetoothEnabled: (() -> Unit)? = null
    ) {
        // check the device whether supporting bluetooth
        if (bluetoothAdapter == null) {
            showToast(com.dhms.basebusiness.R.drawable.ic_fail, "当前设备不支持蓝牙！")
            return
        }

        val permissions = arrayListOf(
            ACCESS_FINE_LOCATION,
            ACCESS_COARSE_LOCATION,
            BLUETOOTH,
            BLUETOOTH_ADMIN,
        )
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            permissions.add(BLUETOOTH_CONNECT)
            permissions.add(BLUETOOTH_SCAN)
        }

        PermissionX.init(this)
            .permissions(permissions)
            .request { allGranted, _, deniedList ->
                if (allGranted) {
                    Log.d(TAG, "All permissions of bluetooth are passed.")
                    // check the bluetooth is or is not enabled
                    if (bluetoothAdapter?.isEnabled == false) {
                        // show a dialog to request to enable bluetooth
                        val intent = Intent(ACTION_REQUEST_ENABLE)
                        requestEnableBluetoothLauncher.launch(intent)
                    } else {
                        if (onBluetoothEnabled != null) {
                            onBluetoothEnabled()
                        }
                    }
                } else {
                    Log.d(TAG, "Permissions are denied: $deniedList.")
                    showToast(com.dhms.basebusiness.R.drawable.ic_fail, "缺少必要权限，请到设置中打开！")
                    if (onBluetoothDisabled != null) {
                        onBluetoothDisabled()
                    }
                    if(deniedList.contains(ACCESS_FINE_LOCATION)||deniedList.contains(ACCESS_COARSE_LOCATION)){
                        showToast(com.dhms.basebusiness.R.drawable.ic_fail, "缺少位置权限，请到设置中打开！")
                    }
                }
            }
    }

    /**
     * Bluetooth's intent receiver class
     */
    @SuppressLint("MissingPermission")
    inner class BluetoothBroadcastReceiver : BroadcastReceiver() {
        private var onBluetoothEnabled: (() -> Unit)? = null
        private var onBluetoothDisabled: (() -> Unit)? = null

        fun setOnBluetoothEnabledListener(onBluetoothEnabled: (() -> Unit)?) {
            this.onBluetoothEnabled = onBluetoothEnabled
        }

        fun setOnBluetoothDisabledListener(onBluetoothDisabled: (() -> Unit)?) {
            this.onBluetoothDisabled = onBluetoothDisabled
        }

        fun clearBluetoothBroadcastReceiverCallbacks() {
            onBluetoothEnabled = null
            onBluetoothDisabled = null
        }

        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                ACTION_STATE_CHANGED -> {
                    when (val state = intent.getIntExtra(EXTRA_STATE, 0)) {
                        STATE_ON -> {
                            Log.d(TAG, "Bluetooth is on.")
                            onBluetoothEnabled?.let {
                                it()
                            }
                        }
                        STATE_OFF -> {
                            Log.d(TAG, "Bluetooth is off.")
                            onBluetoothDisabled?.let {
                                it()
                            }
                        }
                        else ->
                            Log.d(TAG, "Bluetooth state changed: $state")
                    }
                }
                else -> {
                    Log.d(TAG, "Unknown bluetooth state.")
                }
            }
        }
    }

    /**
     * Set the broadcast receiver to listen bluetooth's changed state.
     */
    fun setBluetoothBroadcastReceiver(
        isEnable: Boolean,
        onBluetoothEnabled: (() -> Unit)? = null,
        onBluetoothDisabled: (() -> Unit)? = null
    ) {
        if (isEnable) {
            bluetoothBroadcastReceiver.setOnBluetoothEnabledListener(onBluetoothEnabled)
            bluetoothBroadcastReceiver.setOnBluetoothDisabledListener(onBluetoothDisabled)
            registerReceiver(bluetoothBroadcastReceiver, bluetoothBroadcastIntentFilter)
        } else {
            try {
                unregisterReceiver(bluetoothBroadcastReceiver)
            } catch (e: Exception) {
                Log.d(TAG, "Failed to unregister the bluetoothBroadcastReceiver.")
            }
            bluetoothBroadcastReceiver.clearBluetoothBroadcastReceiverCallbacks()
        }
    }

    override fun onBackPressed() {
        // 手动全屏状态下按返回键则手动恢复竖屏
        if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

            return
        }
        super.onBackPressed()
    }

    override fun onDestroy() {
        clearData()
        LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
        try {
            unregisterReceiver(bluetoothBroadcastReceiver)
        } catch (e: Exception) {
            Log.d(TAG, "Failed to unregister the bluetoothBroadcastReceiver.")
        }
        super.onDestroy()
    }

/*
    override fun onStart() {
        super.onStart()
        checkInstrumentViewModel.setNotToDisconnectDevices(false)
    }

    override fun onStop() {
        if (checkInstrumentViewModel.notToDisconnectDevices.value != true) {
            checkInstrumentViewModel.disconnectDevice()
        }
        super.onStop()
    }
*/

    override fun onResume() {
        super.onResume()
        Log.d(TAG, "onResume: createWebSocket")
        /* 后台 切换 到 前台，判断 socket 链接 */
        WebSocketViewModel.instance.createWebSocket()
    }

   val register=  registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        if(it.resultCode== RESULT_OK){
            it.data?.let { i->
                val str= i.getStringExtra("json")
                str?.let {s->
                    selectMemberEvent.value=s
                }
            }
        }
    }

    companion object {
        private const val TAG = "MainActivity"

        val HOME_NAV_LIST = listOf(
            R.id.deviceCenterFragment,
            R.id.homeFragment,
            R.id.workBenchFragment,
            R.id.mineFragment
        )

        const val TOKEN_EXPIRED_BROADCAST_NAME = "com.dhms.vostok1.TOKEN_EXPIRED"

        class MainBroadcastReceiver(private val onBroadcastReceive: () -> Unit) :
            BroadcastReceiver() {

            private var hasReceived = false

            override fun onReceive(context: Context?, intent: Intent?) {
                if (!hasReceived) {
                    onBroadcastReceive()
                    hasReceived = true
                }
            }
        }
    }
}